﻿Imports System.Linq.Expressions
Imports System.Reflection
Imports System.Text

'http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx

''' <summary>
''' クエリ
''' </summary>
''' <typeparam name="T"></typeparam>
''' <remarks></remarks>
Public Class Query(Of T)
    Implements IQuery(Of T)
    Implements IEnumerable, IEnumerable(Of T)

    Private Sub New()
    End Sub

    Public Sub New(provider As QueryProvider)
#If DEBUG Then
        If provider Is Nothing Then Throw New ArgumentNullException("provider")
#End If
        _provider = provider
    End Sub

    Public Sub New(provider As QueryProvider, expression As Expression)
#If DEBUG Then
        If provider Is Nothing Then Throw New ArgumentNullException("provider")
        If expression Is Nothing Then Throw New ArgumentNullException("expression")
        If Not GetType(IQueryable(Of T)).IsAssignableFrom(expression.Type) Then Throw New ArgumentOutOfRangeException("expression")
#End If
        _provider = provider
    End Sub

#Region "Implements IQuery"
    Private _provider As QueryProvider
    ''' <summary>
    ''' クエリプロバイダー
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Provider() As QueryProvider Implements IQuery.Provider
        Get
            Return _provider
        End Get
        Friend Set(value As QueryProvider)
            _provider = value
        End Set
    End Property
#End Region

#Region "Implements IEnumerable, IEnumerable(Of T)"
    ''' <summary>
    ''' コレクションを反復処理する列挙子を返します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
        Return DirectCast(Me.Provider.Execute(Me), IEnumerable(Of T)).GetEnumerator()
    End Function

    ''' <summary>
    ''' コレクションを反復処理する列挙子を返します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IEnumerable_GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return DirectCast(Me.Provider.Execute(Me), IEnumerable).GetEnumerator()
    End Function
#End Region

    ''' <summary>
    ''' 外部結合を認めるかどうかを示します
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property CanLeftJoin As Boolean Implements IQuery.CanLeftJoin

    ''' <summary>
    ''' カスケードレベルを示します
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property CascadeLevel As Integer Implements IQuery.CascadeLevel

    Private _conditions As New List(Of ICondition)
    ''' <summary>
    ''' 条件を示します
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks>
    ''' Key 　 インスタンス
    ''' Value　インスタンスを探索するリテラルプロパティ
    ''' </remarks>
    Public ReadOnly Property Conditions As IList(Of ICondition) Implements IQuery.Conditions
        Get
            Return _conditions
        End Get
    End Property

    Private _ignoreJoins As New List(Of PropertyInfo)
    ''' <summary>
    ''' 結合条件から外すプロパティを示します
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property IgnoreJoins As IList(Of PropertyInfo) Implements IQuery.IgnoreJoins
        Get
            Return _ignoreJoins
        End Get
    End Property

    ''' <summary>
    ''' リストに変換します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToList() As IList(Of T) Implements IQuery(Of T).ToList
        Return Me.Provider.Execute(Me)
    End Function

    ''' <summary>
    ''' アイテムに変換します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToItem() As T Implements IQuery(Of T).ToItem
        Dim lst = Me.Provider.Execute(Me)
        If lst.Count <> 1 Then Return Nothing
        Return lst(0)
    End Function

    ''' <summary>
    ''' ルートタイプ
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property RootType() As Type Implements IQuery.RootType
        Get
            Return GetType(T)
        End Get
    End Property

End Class
